﻿// -----------------------------------------------------------------------
// <copyright file="Words_Double.cs" company="G.W. van der Vegt">
// SharpForth is inspired by JonesForthInC v1.48 and bb4wForth.
// </copyright>
// -----------------------------------------------------------------------

namespace SharpForth
{
    using System;
    using System.Linq;

    /// <summary>
    /// This static class contains all built-in Forth Words.
    /// </summary>
    public static partial class Words
    {
        #region Double Forth Words

        /// <summary>
        /// .
        /// </summary>
        [WordName("2CONSTANT")]
        [WordSet(WordSets.DOUBLE)]
        [Depends("CREATE")]
        [Depends("DOCOL")]
        [Depends("LIT")]
        [Depends("EXIT")]
        [Syntax("( x1 x2 \"spaces<name>\" --  )")]
        internal static Lazy<DictionaryEntry> TWO_CONSTANT = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("2CONSTANT", 0, delegate
               {
                   CREATE.Value.Invoke();

                   Int32 x2 = Forth.POP_P_STACK();
                   Int32 x1 = Forth.POP_P_STACK();

                   Forth.Dictionary.Last().Definition.Add(Forth.Locate("DOCOL"));
                   Forth.Dictionary.Last().Definition.Add(Forth.Locate("LIT"));
                   Forth.Dictionary.Last().Definition.Add(x2);
                   Forth.Dictionary.Last().Definition.Add(Forth.Locate("LIT"));
                   Forth.Dictionary.Last().Definition.Add(x1);

                   Forth.Dictionary.Last().Definition.Add(Forth.Locate("EXIT"));

                   Forth.NEXT();
               }), true);

        /// <summary>
        /// 2LITERAL takes whatever is on the stack and compiles LIT &lt;foo&gt;.
        /// 
        /// : A [ 22 33 ] 2LITERAL ;
        /// </summary>
        [WordName("2LITERAL")]
        [WordSet(WordSets.DOUBLE)]
        [Depends("IMMEDIATE")]
        [Depends("SWAP")]
        [Depends("[']")]
        [Depends("LIT")]
        [Depends(",")]
        [Syntax("( -- x1 x2 )")]
        internal static String TWO_LITERAL = ": 2LITERAL IMMEDIATE SWAP ['] LIT , , ['] LIT , , ;\n";

        /// <summary>
        /// 
        /// </summary>
        [WordName("2VARIABLE")]
        [WordSet(WordSets.DOUBLE)]
        [Depends("VARIABLE")]
        [Syntax("<word> ( -- addr )")]
        internal static Lazy<DictionaryEntry> TWO_VARIABLE = new Lazy<DictionaryEntry>(
             () => new DictionaryEntry("2VARIABLE", 0, delegate
             {
                 VARIABLE.Value.Invoke();

                 //! The Actual Storage Area.
                 Forth.Dictionary.Last().Definition.Add(0);

                 Forth.NEXT();
             }), true);

        /// <summary>
        /// Adds two double-cell values.
        /// </summary>
        [WordName("D+")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d1|ud1 d2|ud2 -- d3|ud3 )")]
        internal static Lazy<DictionaryEntry> D_PLUS = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D+", 0, delegate
               {
                   UInt64 n2 = Forth.POP_P_STACK_2UD();
                   UInt64 n1 = Forth.POP_P_STACK_2UD();

                   Forth.PUSH_UD2P_STACK(n1 + n2);
               }), true);

        /// <summary>
        /// Substracts two double-cell values.
        /// </summary>
        [WordName("D-")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d1|ud1 d2|ud2 -- d3|ud3 )")]
        internal static Lazy<DictionaryEntry> D_MINUS = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D-", 0, delegate
               {
                   UInt64 n2 = Forth.POP_P_STACK_2UD();
                   UInt64 n1 = Forth.POP_P_STACK_2UD();

                   Forth.PUSH_UD2P_STACK(n1 - n2);
               }), true);

        /// <summary>
        /// Displays a double-cell value.
        /// </summary>
        [WordName("D.")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d -- )")]
        internal static Lazy<DictionaryEntry> D_DOT = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D.", 0, delegate
               {
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.DoOutput("{0}", d1);
               }), true);

        /// <summary>
        /// Displays a double-cell value.
        /// </summary>
        [WordName("D.R")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d n -- )")]
        internal static Lazy<DictionaryEntry> D_DOT_R = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D.R", 0, delegate
               {
                   Int64 d1 = Forth.POP_P_STACK_2D();
                   Int32 n = Forth.POP_P_STACK();

                   Forth.DoOutput("{0}", d1.ToString().PadLeft(n));
               }), true);

        /// <summary>
        /// Test if double-cell value &lt; 0.
        /// </summary>
        [WordName("D0<")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d -- flag )")]
        internal static Lazy<DictionaryEntry> D_ZERO_LESS = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D0<", 0, delegate
               {
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_P_STACK(d1 < 0 ? Forth.FORTH_TRUE : Forth.FORTH_FALSE);
               }), true);

        /// <summary>
        /// Test if double-cell value = 0.
        /// </summary>
        [WordName("D0=")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( xd -- flag )")]
        internal static Lazy<DictionaryEntry> D_ZERO_EQUALS = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D0=", 0, delegate
               {
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_P_STACK(d1 == 0 ? Forth.FORTH_TRUE : Forth.FORTH_FALSE);
               }), true);

        /// <summary>
        /// Shifts a double cell left (so multiply by 2).
        /// </summary>
        [WordName("D2*")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( xd1 -- xd2 )")]
        internal static Lazy<DictionaryEntry> D_TWO_STAR = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D2*", 0, delegate
               {
                   UInt64 n1 = Forth.POP_P_STACK_2UD();

                   Forth.PUSH_UD2P_STACK(n1 << 1);
               }), true);

        /// <summary>
        /// .
        /// </summary>
        [WordName("D2/")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( xd1 -- xd2 )")]
        internal static Lazy<DictionaryEntry> DTWO_SLASH = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D2/", 0, delegate
               {
                   UInt64 n1 = Forth.POP_P_STACK_2UD();

                   Forth.PUSH_UD2P_STACK(n1 >> 1);
               }), true);

        /// <summary>
        /// Test if double-cell value1 &lt; value2.
        /// </summary>
        [WordName("D<")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d1 d2 -- flag )")]
        internal static Lazy<DictionaryEntry> D_LESS_THAN = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D<", 0, delegate
               {
                   Int64 d2 = Forth.POP_P_STACK_2D();
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_P_STACK(d1 < d2 ? Forth.FORTH_TRUE : Forth.FORTH_FALSE);
               }), true);

        /// <summary>
        /// Test if double-cell value1 equals value2.
        /// </summary>
        [WordName("D=")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( xd1 xd2  -- flag )")]
        internal static Lazy<DictionaryEntry> D_EQUALS = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D<", 0, delegate
               {
                   Int64 d2 = Forth.POP_P_STACK_2D();
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_P_STACK(d1 == d2 ? Forth.FORTH_TRUE : Forth.FORTH_FALSE);
               }), true);

        /// <summary>
        /// Converts a double-cell value back to a single-cell one.
        /// </summary>
        [WordName("D>S")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d  -- n )")]
        internal static Lazy<DictionaryEntry> D_TO_S = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("D<", 0, delegate
               {
                   Int64 d = Forth.POP_P_STACK_2D();

                   Forth.PUSH_P_STACK((Int32)d);
               }), true);

        /// <summary>
        /// Returns the absolute value of a double-cell value.
        /// </summary>
        [WordName("DABS")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d  -- ud )")]
        internal static Lazy<DictionaryEntry> D_ABS = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("DABS", 0, delegate
               {
                   Int64 d = Forth.POP_P_STACK_2D();

                   Forth.PUSH_D2P_STACK(Math.Abs(d));
               }), true);

        /// <summary>
        /// Returns the max of two double-cell values.
        /// </summary>
        [WordName("DMAX")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d1 d2  -- d3 )")]
        internal static Lazy<DictionaryEntry> D_MAX = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("DMAX", 0, delegate
               {
                   Int64 d2 = Forth.POP_P_STACK_2D();
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_D2P_STACK(d1 > d2 ? d1 : d2);
               }), true);

        /// <summary>
        /// Returns the min of two double-cell values.
        /// </summary>
        [WordName("DMIN")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d1 d2  -- d3 )")]
        internal static Lazy<DictionaryEntry> D_MIN = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("DMIN", 0, delegate
               {
                   Int64 d2 = Forth.POP_P_STACK_2D();
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_D2P_STACK(d1 < d2 ? d1 : d2);
               }), true);

        /// <summary>
        /// Negates a double-cell value.
        /// </summary>
        [WordName("DNEGATE")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d1 -- d2 )")]
        internal static Lazy<DictionaryEntry> D_NEGATE = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("DNEGATE", 0, delegate
               {
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_D2P_STACK(-d1);
               }), true);

        /// <summary>
        /// 
        /// </summary>
        [WordName("M*/")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d1 n1 +n2 -- d2 )")]
        internal static Lazy<DictionaryEntry> M_STAR_SLASH = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("M*/", 0, delegate
               {
                   Int32 n2 = Forth.POP_P_STACK();
                   Int32 n1 = Forth.POP_P_STACK();
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_D2P_STACK(d1 * n1 / n2);
               }), true);

        /// <summary>
        /// 
        /// </summary>
        [WordName("M+")]
        [WordSet(WordSets.DOUBLE)]
        [Syntax("( d1|ud1 n -- d2|ud2 )")]
        internal static Lazy<DictionaryEntry> M_PLUS = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("M+", 0, delegate
               {
                   Int32 n = Forth.POP_P_STACK();
                   Int64 d1 = Forth.POP_P_STACK_2D();

                   Forth.PUSH_D2P_STACK(d1 + n);
               }), true);

        /// <summary>
        /// 
        /// </summary>
        [WordName("2ROT")]
        [WordSet(WordSets.DOUBLE_EXT)]
        [Syntax("( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )")]
        internal static Lazy<DictionaryEntry> TWO_ROTE = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("2ROT", 0, delegate
               {
                   Int64 d1 = Forth.POP_P_STACK_2D(); // x5 x6
                   Int64 d2 = Forth.POP_P_STACK_2D(); // x3 x4
                   Int64 d3 = Forth.POP_P_STACK_2D(); // x1 x2

                   Forth.PUSH_D2P_STACK(d2);
                   Forth.PUSH_D2P_STACK(d1);
                   Forth.PUSH_D2P_STACK(d3);
               }), true);

        /// <summary>
        /// 
        /// </summary>
        [WordName("DU<")]
        [WordSet(WordSets.DOUBLE_EXT)]
        [Syntax("( ud1 ud2 -- flag )")]
        internal static Lazy<DictionaryEntry> D_U_LESS = new Lazy<DictionaryEntry>(
               () => new DictionaryEntry("DU<", 0, delegate
               {
                   UInt64 n2 = Forth.POP_P_STACK_2UD(); // ud2
                   UInt64 n1 = Forth.POP_P_STACK_2UD(); // ud1

                   Forth.PUSH_P_STACK(n1 < n2 ? Forth.FORTH_TRUE : Forth.FORTH_FALSE);
               }), true);

        #endregion Double Forth Words
    }
}
